home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xconq
/
curses.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-09
|
10KB
|
459 lines
/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */
/* This program may be used, copied, modified, and redistributed freely */
/* for noncommercial purposes, so long as this notice remains intact. */
#pragma comment(exestr, "@(#) curses.c 12.1 95/05/09 ")
/* RCS $Header: curses.c,v 1.2 88/07/17 15:26:31 shebs Exp $ */
/* Interface implementations for the curses version of xconq. */
/* This file is rather simple, since there is no support for multiple */
/* displays, no flashy graphics, and very little optimization. */
#include "config.h"
#include "misc.h"
#include "period.h"
#include "side.h"
#include "map.h"
#undef bool /* ugh */
#include <curses.h>
#ifdef UNIX
#include <signal.h> /* needed for ^C handling */
#endif /* UNIX */
#define INFOLINES 4
int helpwinlines = 1;
/* Positions and sizes of the windows. */
int wx[20], wy[20], ww[20], wh[20];
int nextwin = 0; /* number of next window to open */
bool alreadyopen = FALSE; /* flag to prevent double opening */
/* Put in a default player, probably the invoker of the program. */
/* Nonempty host name not actually used, but needed to keep things */
/* straight. */
add_default_player()
{
add_player(TRUE, "curses");
}
/* Decide what to do about ^C interrupts. */
#ifdef UNIX
stop_handler()
{
if (numhumans == 0 || Debug) {
close_displays();
exit(1);
}
}
#endif /* UNIX */
init_sighandlers()
{
#ifdef UNIX
signal(SIGINT, stop_handler);
#endif /* UNIX */
}
/* "Opening" a curses "display" just involves a standard sequence of calls. */
/* Unfortunately, the "standard sequence" varies from system to system... */
open_display(side)
Side *side;
{
if (!alreadyopen) {
initscr();
nonl();
noecho();
#ifdef USECBREAK
cbreak();
#endif /* USECBREAK */
#ifdef USECRMODE
crmode();
#endif /* USECRMODE */
clear();
side->display = 1L;
alreadyopen = TRUE;
return TRUE;
} else {
/* if we got here, we're in big trouble, so clean up quickly */
clear();
refresh();
endwin();
printf("Can't open a second display!\n");
return FALSE;
}
}
/* A predicate that tests whether our display can safely be written to. */
/* This is permitted to do side-effects, although curses doesn't need */
/* anything special. */
active_display(side)
Side *side;
{
return (side != NULL && side->host && !side->lost && side->display);
}
/* Display will use every character position we can get our hands on. */
display_width(side) Side *side; { return COLS; }
display_height(side) Side *side; { return LINES; }
/* Displaying the world map usually requires a large bitmap display. */
world_display(side) Side *side; { return FALSE; }
/* Most sizes of things are 1 (i.e. one character cell). */
init_misc(side)
Side *side;
{
side->fw = side->fh = side->hh = side->hch = side->uw = side->uh = 1;
side->hw = 2;
side->bd = side->margin = 0;
}
/* The "root window" covers our entire display. In theory, the size of the */
/* screen could exceed what xconq needs, but this is wildly improbable. */
create_main_window(side)
Side *side;
{
create_window(side, 0, 0, COLS, LINES);
}
/* Subwindow creator. */
create_window(side, x, y, w, h)
Side *side;
int x, y, w, h;
{
if (x + w > COLS) w = COLS - x;
if (y + h > LINES) h = LINES - y;
wx[nextwin] = x; wy[nextwin] = y;
ww[nextwin] = w; wh[nextwin] = h;
return (nextwin++);
}
/* Help window has to be larger than most terminals allow, so blow it off. */
create_help_window(side) Side *side; {}
/* No special fixups to do. */
fixup_windows(side) Side *side; {}
enable_input(side) Side *side; {}
reset_misc(side) Side *side; {}
/* Moving a window just involves plugging in new values. */
change_window(side, win, x, y, w, h)
Side *side;
int win, x, y, w, h;
{
if (x + w > COLS) w = COLS - x;
if (y + h > LINES) h = LINES - y;
if (x >= 0) {
wx[win] = x; wy[win] = y;
}
if (w >= 0) {
ww[win] = w; wh[win] = h;
}
}
/* Actually, terminals are really "one-color", but don't take a chance on */
/* confusing the main program. */
display_colors(side) Side *side; { return 2; }
white_color(side) Side *side; { return 1; }
black_color(side) Side *side; { return 0; }
/* Can't actually honor any color requests... */
request_color(side, name) Side *side; char *name; { return 0; }
/* Only kind of input is keystrokes, and from only one "display" at that. */
get_input()
{
char ch;
extern Side *curside;
if (active_display(curside)) {
draw_cursor(curside);
ch = getch() & 0177;
curside->reqtype = KEYBOARD;
curside->reqch = ch;
return TRUE;
}
}
/* Wait for any input, don't care what it is. */
freeze_wait(side)
Side *side;
{
refresh();
getch();
}
/* Actually would be nice to do something reasonable here. */
flush_input(side) Side *side; {}
/* Trivial abstraction - sometimes other routines like to ensure all output */
/* actually on the screen. */
flush_output(side) Side *side; { refresh(); }
/* General window clearing. */
clear_window(side, win)
Side *side;
int win;
{
int i;
if (wx[win] == 0 && wy[win] == 0 && ww[win] == COLS && wh[win] == LINES) {
clear();
} else {
for (i = 0; i < ww[win]; ++i) tmpbuf[i] = ' ';
tmpbuf[ww[win]] = '\0';
for (i = 0; i < wh[win]; ++i) mvaddstr(wy[win]+i, wx[win], tmpbuf);
}
}
/* No world display for curses. */
draw_bar(side, x, y, len, color) Side *side; int x, y, len, color; {}
invert_box(side, vcx, vcy) Side *side; int vcx, vcy; {}
/* This interfaces higher-level drawing decisions to the rendition of */
/* individual pieces of display. Note that a display mode determines */
/* whether one or two terrain characters get drawn. */
draw_terrain_row(side, x, y, buf, len, color)
Side *side;
int x, y, len, color;
char *buf;
{
int i, xi = x;
for (i = 0; i < len; ++i) {
if (xi >= wx[side->map] + ww[side->map] - 2) break;
if (cur_at(side->map, xi, y)) {
addch(buf[i]);
addch((side->showmode == BORDERHEX ? ' ' : buf[i]));
}
xi += 2;
}
}
/* Don't just position the cursor, but also clip and return the decision. */
cur_at(win, x, y)
int win, x, y;
{
if (x < 0 || x >= ww[win] || y < 0 || y >= wh[win]) {
return FALSE;
} else {
move(wy[win] + y, wx[win] + x);
return TRUE;
}
}
/* Curses is never flashy... */
flash_position(side, x, y, tm) Side *side; int x, y, tm; {}
/* Curses cursor drawing is quite easy! (but ineffective? - see input fns) */
draw_cursor_icon(side, x, y)
Side *side;
int x, y;
{
cur_at(side->map, x, y);
refresh();
}
/* Doesn't seem to be necessary. */
draw_hex_icon(side, win, x, y, color, ch)
Side *side;
int win, x, y, color;
char ch;
{
}
/* Splash a unit character onto some window. */
draw_unit_icon(side, win, x, y, u, color)
Side *side;
int win;
int x, y, u, color;
{
if (cur_at(win, x, y)) {
addch(utypes[u].uchar);
addch(' '); /* inefficient, sigh */
}
}
/* Use the second position in a "hex" for identification of enemies. */
draw_side_number(side, win, x, y, n, color)
Side *side;
int win, x, y, n, color;
{
if (cur_at(win, x+1, y)) addch((n == -1) ? '`' : n + '0');
}
/* Curses has enough trouble splatting stuff on the screen without doing */
/* little flashes too... */
draw_blast_icon(side, win, x, y, type, color)
Side *side;
int win, x, y, type, color;
{
}
/* Unfortunately, terminals usually can't flash their screens. */
invert_whole_map(side) Side *side; {}
/* Mushroom clouds don't come out real well either. */
/* This could be a little more elaborate. */
draw_mushroom(side, x, y, i)
Side *side;
int x, y, i;
{
int sx, sy;
xform(side, unwrap(side, x), y, &sx, &sy);
if (cur_at(side->map, sx, sy)) {
addstr("##");
flush_output(side);
if (i > 0) {
if (cur_at(side->map, sx-1, sy+1)) addstr("####");
if (cur_at(side->map, sx-2, sy)) addstr("######");
if (cur_at(side->map, sx-1, sy-1)) addstr("####");
flush_output(side);
}
}
}
/* Indicate that bar graphs are out of the question. */
bar_graphs(side) Side *side; { return FALSE; }
/* Thus this routine can be empty. */
draw_graph(side, number, amount, total, title)
Side *side;
int number, amount, total;
{
}
/* Drawing text is easy, as long as we can ignore the color of it. */
/* Need to do manual clipping though. */
draw_text(side, win, x, y, str, color)
Side *side;
int win;
int x, y, color;
char *str;
{
int i;
if (cur_at(win, x, y)) {
for (i = 0; i < strlen(str); ++i) {
if (x + i >= ww[win]) return;
addch(str[i]);
}
}
}
/* Can't draw lines, but this will substitute, sort of. */
draw_scratchout(side, pos)
Side *side;
int pos;
{
int i;
for (i = 0; i < 20; i += 2) {
if (cur_at(side->sides, i, pos)) addch('-');
}
}
/* Beep the beeper! */
beep(side)
Side *side;
{
putchar('\007');
}
/* Most help info is printable also. */
reveal_help(side)
Side *side;
{
notify(side, "Screen too small - writing into files instead.");
do_printables(side, 0);
return FALSE;
}
conceal_help(side) Side *side; {}
/* Shut a single display down - presumably only called once. */
close_display(side)
Side *side;
{
clear();
refresh();
endwin();
side->display = 0;
}
/* Completely redo a screen, making no assumptions about appearance. */
/* This one is used frequently, especially when a window is exposed. */
redraw(side)
Side *side;
{
if (active_display(side)) {
erase_cursor(side);
clear_window(side, side->main);
show_note(side);
show_info(side);
show_prompt(side);
show_all_sides(side);
show_timemode(side);
show_clock(side);
show_state(side);
show_map(side);
show_world(side);
flush_output(side);
flush_input(side);
}
}